'''
Created on Jan 30, 2012

@author: Deepak Patil
'''
from ConfigReader import WAFConfig
from Analyzer import SClass, SField, SGlobal, SMethod
from Analyzer import SHelper
from JavaLangAST import Type, ClassOrInterfaceType, PrimitiveType, Method
class ST:
    JHcls=None
    stringToJSON=None
    encodeString=None
    stringArrayToJSONString=None
    sharedTypeArrayToJSONString=None
    jsonser_toJSON=None
    jsonser_fromJSON=None
    
    @staticmethod
    def getJS_fromJSONCode(cls):
        from Java2js import SA, getFormatedCode 
        ST.init()        
        code=[]
        code.append("function(d){")
        declare_var=False
        cc=[]        
        for f in cls.fields:            
            f=cls.fields[f]        
            if f.isStatic():continue
            name=None
            name=f.getJSName()            
            p=f.type        
            if SA.isBasicType(p) or SA.isStringType(p) or SA.isSingleDimentionBasicTypeArray(p):
                cc.append("this."+name+"=d."+name+";");
            elif SA.isSharedType(p):
                tcls=p.coit.clazz
                cons=tcls.getConstructor([],cls)            
                if cons==None:
                    raise Exception("Empty Constructor not found for shared type "+tcls.getFullname())
                method=None
                for m in tcls.methods:
                    if m.name=="fromJSON":
                        method=m
                        break
                cc.append("if(d."+name+"!=null){")
                cc.append("var o=(new " + tcls.getPrototype() + "())." + cons.getJSName() + "();")                
                cc.append("o."+method.getJSName()+"(d."+name+");")
                cc.append("this."+name+"=o;")
                cc.append("}")
                cc.append("else")
                cc.append("this.name=null;")
            elif SA.isArrayOfSharedType(p):
                tcls=p.coit.next.coit.clazz
                cons=tcls.getConstructor([],cls)
                if cons==None:
                    raise Exception("Empty Constructor not found for shared type "+tcls.getFullname())
                method=None
                for m in tcls.methods:
                    if m.name=="fromJSON":
                        method=m
                        break
                cc.append("this."+name+"=[];")
                declare_var=True
                cc.append("if(d."+name+"!=null){")
                cc.append("l=d."+name+".length;")
                cc.append("for(i=0;i<l;i++){")
                cc.append("if(d."+name+"[i]!=null){")
                cc.append("var o=(new " + tcls.getPrototype() + "())." + cons.getJSName() + "();")
                cc.append("o."+method.getJSName()+"(d."+name+"[i]);")
                cc.append("this."+name+".push(o);")
                cc.append("}else")
                cc.append("this."+name+".push(null);")                
                cc.append("}")
                cc.append("}")
            else:
                raise Exception ("Non basic types not supported")                    
        if declare_var==True:
            cc.append("var i,l;")    
        code.append(cc)
        code.append("}")
        return code
    @staticmethod
    def init():
        if ST.JHcls==None:
            ST.JHcls=SHelper.getClassOnFullName("com.openwaf.core.framework.JSONHelper")
            ST.stringToJSON=ST.JHcls.getMethodWithThisAccess("stringToJSON", [SGlobal.stringclass.mytype], True, None,None)
            ST.encodeString=ST.JHcls.getMethodWithThisAccess("encodeString", [SGlobal.stringclass.mytype], True, None,None)            
            t=Type()
            t.coit=ClassOrInterfaceType()            
            t.coit.clazz=SGlobal.arrayclass
            t.coit.next=SGlobal.stringclass.mytype
            ST.stringArrayToJSONString=ST.JHcls.getMethodWithThisAccess("stringArrayToJSONString", [t], True, None,None)
            jsonser=SHelper.getClassOnFullName("com.openwaf.server.JSONSerializable")
            ###            
            for m in jsonser.methods:
                if m.name=="toJSON":
                    ST.jsonser_toJSON=m.method
                if m.name=="fromJSON":
                    ST.jsonser_fromJSON=m.method
            ###
            t.coit.next=jsonser.mytype
            ST.sharedTypeArrayToJSONString=ST.JHcls.getMethodWithThisAccess("sharedTypeArrayToJSONString",[t],True,None,None)
            pline=ST.JHcls.getPrototype();            
            ST.stringToJSON=pline+".$."+ST.stringToJSON.method.getJSName();
            ST.encodeString=pline+".$."+ST.encodeString.method.getJSName();
            ST.stringArrayToJSONString=pline+".$."+ST.stringArrayToJSONString.method.getJSName();
            ST.sharedTypeArrayToJSONString=pline+".$."+ST.sharedTypeArrayToJSONString.method.getJSName();
    @staticmethod
    def getJS_toJSONCode(cls):
        from Java2js import SA, getFormatedCode                             
        ST.init()
        code=[]
        code.append("function(){")
        cons=cls.getConstructor([],cls)
        cc=[]        
        cc.append("var d=[];")
        for f in cls.fields:
            f=cls.fields[f]       
            if f.isStatic():continue 
            line=None
            name=None
            name=f.getJSName()
            line="\""+name+"\"+':'+"
            p=f.type        
            if SA.isBasicType(p):
                line+="d."+name
                cc.append("d.push("+line+");");
            elif SA.isStringType(p):
                line+=ST.stringToJSON+"(d."+name+")"
                cc.append("d.push("+line+");");
            elif SA.isSingleDimentionBasicTypeArray(p):
                line+=ST.stringArrayToJSONString+"(d."+name+")"
                cc.append("d.push("+line+");");
            elif SA.isSharedType(p):
                tcls=p.coit.clazz            
                if cons==None:
                    raise Exception("Empty Constructor not found for shared type "+tcls.getFullname())
                method=tcls.getMethodWithThisAccess("toJSON", [], False, None,cls)
                cc.append("if(d."+name+"!=null)")
                line+="d."+name+"."+method.method.getJSName()+"()"
                cc.append("d.push("+line+");");
                cc.append("else")
                cc.append("d.push(null);")
            elif SA.isArrayOfSharedType(p):
                line+=ST.sharedTypeArrayToJSONString+"(d."+name+")"
                cc.append("d.push("+line+");");
            else:
                raise Exception ("Non basic types not supported")
            
        cc.append("return '{'+d.join(',')+'}';")    
        code.append(cc)
        code.append("}")
        return code
    @staticmethod
    def toJava_toJSONCode(cls):
        from Java2js import SA, getFormatedCode
        code=[]                
        cc=[]
        
        cc.append("JSONObject jo=new JSONObject();")
        declare_vars=False
        for f in cls.fields:
            f=cls.fields[f] 
            if f.isStatic():continue                               
            name=None
            name=f.getJSName()                     
            p=f.type        
            if SA.isBasicType(p) or SA.isStringType(p):
                cc.append("jo.put(\""+name+"\","+f.name+");")            
            elif SA.isSingleDimentionBasicTypeArray(p):
                declare_vars=True
                cc.append("ja=new org.json.JSONArray();")
                cc.append("l="+f.name+".length;")
                cc.append("for(i=0;i<l;i++){")
                cc.append(["ja.put("+f.name+"[i]);"])
                cc.append("}")
                cc.append("jo.put(\""+name+"\",ja);")
            elif SA.isSharedType(p):
                cc.append("if("+f.name+"!=null)")
                cc.append("jo.put(\""+name+"\","+f.name+".toJSON());")
                #cc.append("else")
                #cc.append("jo.put(\""+name+"\",null);")
            elif SA.isArrayOfSharedType(p):
                declare_vars=True
                cc.append("if("+f.name+"!=null){")
                cc.append("ja=new org.json.JSONArray();")
                cc.append("l="+f.name+".length;")
                cc.append("for(i=0;i<l;i++){")
                cc.append("if("+f.name+"[i]!=null)")
                cc.append(["ja.put("+f.name+"[i].toJSON());"])
                #cc.append("else")
                #cc.append(["ja.put(null);"])
                cc.append("}")
                cc.append("jo.put(\""+name+"\",ja);")
                cc.append("}")
                #cc.append("else")
                #cc.append("jo.put(\""+name+"\",null);")
            else:
                raise Exception ("Non basic types not supported")        
        if declare_vars==True:
            code.append(["org.json.JSONArray ja;"])
            code.append(["int l,i;"])
        cc.append("return jo;")          
        code.append(cc)
        return code
        
    @staticmethod
    def toJava_fromJSONCode(cls):
        from Java2js import SA, getFormatedCode
        code=[]                
        cc=[]
                
        declare_vars=False
        for f in cls.fields:
            f=cls.fields[f]
            if f.isStatic():continue                              
            name=None
            name=f.getJSName()                       
            p=f.type                    
            if SA.isBasicType(p) or SA.isStringType(p):
                if SA.isStringType(p):
                    cc.append(f.name+"=jo.getString(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.BOOLEAN:
                    cc.append(f.name+"=jo.getBoolean(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.INT:
                    cc.append(f.name+"=jo.getInt(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.BYTE:
                    cc.append(f.name+"=(byte)jo.getInt(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.CHAR:
                    cc.append(f.name+"=(char)jo.getInt(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.DOUBLE:
                    cc.append(f.name+"=jo.getDouble(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.FLOAT:
                    cc.append(f.name+"=(float)jo.getDouble(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.LONG:
                    cc.append(f.name+"=jo.getLong(\""+name+"\");")
                elif p.pm_type.value==PrimitiveType.SHORT:
                    cc.append(f.name+"=(short)jo.getInt(\""+name+"\");")                
            elif SA.isSingleDimentionBasicTypeArray(p):
                declare_vars=True
                cc.append("ja=jo.getJSONArray(\""+name+"\");")
                cc.append("l=ja.length();")
                t=p.coit.next
                if SA.isStringType(t):
                    cc.append(f.name+"=new String[l];")
                else:
                    cc.append(f.name+"=new "+PrimitiveType.toJ(t.pm_type.value)+"[l];")
                cc.append("for(i=0;i<l;i++){")
                  
                if SA.isStringType(t):
                    cc.append(f.name+"[i]=ja.getString(i);")
                elif t.pm_type.value==PrimitiveType.BOOLEAN:
                    cc.append(f.name+"[i]=ja.getBoolean(i);")
                elif t.pm_type.value==PrimitiveType.INT:
                    cc.append(f.name+"[i]=ja.getInt(i);")
                elif t.pm_type.value==PrimitiveType.BYTE:
                    cc.append(f.name+"[i]=(byte)ja.getInt(i);")
                elif t.pm_type.value==PrimitiveType.CHAR:
                    cc.append(f.name+"[i]=(char)ja.getInt(i);")
                elif t.pm_type.value==PrimitiveType.DOUBLE:
                    cc.append(f.name+"[i]=ja.getDouble(i);")
                elif t.pm_type.value==PrimitiveType.FLOAT:
                    cc.append(f.name+"[i]=(float)ja.getDouble(i);")
                elif t.pm_type.value==PrimitiveType.LONG:
                    cc.append(f.name+"[i]=ja.getLong(i);")
                elif t.pm_type.value==PrimitiveType.SHORT:
                    cc.append(f.name+"[i]=(short)ja.getInt(i);")                              
                cc.append("}")                
            elif SA.isSharedType(p):
                cc.append(f.name+"=new "+p.coit.clazz.fullname+"();")
                cc.append(f.name+".fromJSON(jo.getJSONObject(\""+name+"\"));")
            elif SA.isArrayOfSharedType(p):
                declare_vars=True
                cc.append("ja=jo.getJSONArray(\""+name+"\");")
                cc.append("l=ja.length();")
                t=p.coit.next
                cc.append(f.name+"=new "+t.coit.clazz.fullname+"[l];")              
                cc.append("for(i=0;i<l;i++){")
                cc.append(f.name+"[i]=new "+t.coit.clazz.fullname+"();")
                cc.append(f.name+"[i].fromJSON(ja.getJSONObject(i));")                  
                cc.append("}")      
            else:
                raise Exception ("Non basic types not supported")        
        if declare_vars==True:
            code.append(["org.json.JSONArray ja;"])
            code.append(["int l,i;"])      
        code.append(cc)
        return code   
    @staticmethod
    def getCodeSharedTypeJavaFile(cls,filepath):
        from Java2js import SA, getFormatedCode
        method_toJSON=None
        method_fromJSON=None
        for m in cls.methods:
            if m.name=="toJSON":
                method_toJSON=m.method
            if m.name=="fromJSON":
                method_fromJSON=m.method
        if method_fromJSON==None or method_toJSON==None:
            raise Exception("toJSON/fromJSON method not defined in "+cls.fullname)
        cc=[]
        line=open(filepath,"rb").read()
        lines=line.split("\n")
        l=len(lines)
        count=0
        while count<l:
            if count==(method_fromJSON.line_start-1):
                cc.append(["public void fromJSON(JSONObject jo) throws Exception{"])
                cc.append(getFormatedCode(ST.toJava_fromJSONCode(cls), 4))             
                cc.append(["}"])
                count=method_fromJSON.line_end-1
            elif count==(method_toJSON.line_start-1):
                cc.append(["public JSONObject toJSON() throws Exception {"])
                cc.append(getFormatedCode(ST.toJava_toJSONCode(cls), 4))             
                cc.append(["}"])
                count=method_toJSON.line_end-1
            else:
                cc.append(lines[count])
                count+=1
        return getFormatedCode(cc,0)
            
            
        
                
        
        
        

    
        
             
        
    
    